﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace NetFtp.Core.Ftp
{
    /// <summary>
    /// Connexion d'un utilisateur à un compte FTP.
    /// </summary>
    public class FtpSession
    {
        private FtpLogin ftpLogin;
        private Uri hostname;
        private Uri basename;
        private bool passive;

        /// <summary>
        /// Nom d'utilisateur, mot de passe utilisé pour l'authentification FTP.
        /// </summary>
        public FtpLogin FtpLogin
        {
            get
            {
                return ftpLogin;
            }
        }

        /// <summary>
        /// Répertoire par défaut du FTP.
        /// </summary>
        public Uri Basename
        {
            get
            {
                return basename;
            }
            set
            {
                basename = new Uri(hostname, value);
            }
        }

        /// <summary>
        /// Crée une nouvelle session FTP.
        /// </summary>
        /// <param name="hostname">Nom d'hôte du serveur FTP</param>
        /// <param name="port">Numéro du port</param>
        /// <param name="username">Nom d'utilisateur pour l'authentification</param>
        /// <param name="password">Mot de passe utilisé pour l'authentification</param>
        public FtpSession(string hostname, int port, string username, string password)
        {
            ftpLogin = new FtpLogin(username, password);
            this.hostname = new Uri("ftp://" + hostname);
            basename = new Uri(this.hostname, "/"); // le nom de dossier par défault est la racine FTP
            this.passive = true;
        }

        /// <summary>
        /// Crée une nouvelle session FTP.
        /// </summary>
        /// <param name="hostname">Nom d'hôte du serveur FTP</param>
        /// <param name="port">Numéro du port</param>
        /// <param name="username">Nom d'utilisateur pour l'authentification</param>
        /// <param name="password">Mot de passe utilisé pour l'authentification</param>
        public FtpSession(string hostname, int port, string username, string password, bool passive)
        {
            ftpLogin = new FtpLogin(username, password);
            this.hostname = new Uri("ftp://" + hostname);
            basename = new Uri(this.hostname, "/"); // le nom de dossier par défault est la racine FTP
            this.passive = passive;
        }

        /// <summary>
        /// Télécharge le fichier local source vers la destination sur le serveur FTP.
        /// </summary>
        /// <param name="source">Chemin absolu du fichier</param>
        /// <param name="dest">Chemin relatif de la destination (par rapport à Basename)</param>
        public void Upload(string source, string dest)
        {
            Uri destUri = new Uri(hostname, dest);
            FtpOperation.DoUpload(ftpLogin, source, destUri, passive);
        }

        /// <summary>
        /// Télécharge le fichier distant vers la source en local.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="dest"></param>
        public void Download(string source, string dest)
        {
            FtpOperation.DoDownload(ftpLogin, new Uri(hostname, source), dest, passive);
        }

        /// <summary>
        /// Retourne le contenu du répertoire spécifié.
        /// </summary>
        /// <param name="directory">Le répertoire à lister</param>
        /// <returns>Le contenu sous forme d'une liste de nom</returns>
        public IList<FtpFile> ListDirectory(string directory)
        {
            NormalizeDirectory(ref directory);
            return FtpOperation.DoListDirectory(ftpLogin, new Uri(hostname, directory), passive);
        }

        /// <summary>
        /// Liste les répertoires contenu dans ce répertoire.
        /// </summary>
        /// <param name="directory"></param>
        /// <returns></returns>
        public IList<FtpFile> ListDirectoryDirOnly(string directory)
        {
            NormalizeDirectory(ref directory);
            return FtpOperation.DoListDirectory(ftpLogin, new Uri(hostname, directory), FtpOperation.ListDirectoryKind.DIRECTORY_ONLY, passive);
        }

        /// <summary>
        /// Liste les uniquement les fichiers de ce répertoire.
        /// </summary>
        /// <param name="directory"></param>
        /// <returns></returns>
        public IList<FtpFile> ListDirectoryFileOnly(string directory)
        {
            NormalizeDirectory(ref directory);
            return FtpOperation.DoListDirectory(ftpLogin, new Uri(hostname, directory), FtpOperation.ListDirectoryKind.FILE_ONLY, passive);
        }

        /// <summary>
        /// Supprime un fichier
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public void DeleteFile(string file)
        {
            FtpOperation.DoDeleteFile(ftpLogin, new Uri(hostname, file), passive);
        }

        /// <summary>
        /// Supprime un dossier
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public void DeleteDirectory(string directory)
        {
            FtpOperation.DoDeleteDirectory(ftpLogin, new Uri(hostname, directory), passive);
        }

        /// <summary>
        /// Cré un dossier
        /// </summary>
        /// <param name="folder"></param>
        /// <returns></returns>
        public void MakeDirectory(string directory)
        {
            FtpOperation.DoMakeDirectory(ftpLogin, new Uri(hostname, directory), passive);
        }

        /// <summary>
        /// Renommer un fichier
        /// </summary>
        /// <param name="file"></param>
        /// <param name="newname"></param>
        /// <returns></returns>
        public void RenameFile(string file, string newname)
        {
            FtpOperation.DoRenameFile(ftpLogin, new Uri(hostname, file), newname, passive);
        }

        /// <summary>
        /// Ajoute le "/" à la fin si il n'existe pas.
        /// </summary>
        /// <param name="directory"></param>
        private static void NormalizeDirectory(ref string directory)
        {
            if (!directory.EndsWith("/"))
            {
                directory += "/";
            }
        }

        /// <summary>
        /// Retourne le mode
        /// </summary>
        public bool Passive
        {
            get
            {
                return FtpOperation.PassiveMode(ftpLogin, new Uri(hostname, basename));
            }
        }
    }
}
